/*
 * @(#)SOAPTransactionHandler.java
 * Date 2014-01-12
 * Version 1.0
 * Author Jim Horner
 * Copyright (c)2012
 */


package us.hornerscorners.lamppost.ws;

import java.util.Set;

import javax.xml.namespace.QName;

import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;

import javax.xml.ws.handler.MessageContext;

import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


/**
 * Class description
 *
 *
 * @version        v1.0, 2014-01-12
 * @author         Jim Horner
 */
public class SOAPTransactionHandler implements SOAPHandler<SOAPMessageContext> {

    /** Field description */
    public static final String TRANSACTION_CONTEXT =
        "SOAPTransactionHandler-TRANSACTION_CONTEXT";

    /** Field description */
    public static final String URI = "http://hornerscorners.us/lamppost/transaction";

    /** Field description */
    private TransactionContext context;

    /** Field description */
    private final Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * Constructs ...
     *
     */
    public SOAPTransactionHandler() {
        super();
    }

    /**
     * Constructs ...
     *
     *
     * @param context
     */
    public SOAPTransactionHandler(TransactionContext context) {

        super();
        this.context = context;
    }

    /**
     *  Method description
     *
     *
     *  @param context
     */
    @Override
    public void close(MessageContext context) {

        //
    }

    /**
     * Method description
     *
     *
     * @return
     */
    @Override
    public Set<QName> getHeaders() {

        return null;
    }

    /**
     * Method description
     *
     *
     * @param context
     *
     * @return
     */
    @Override
    public boolean handleFault(SOAPMessageContext context) {

        return true;
    }

    /**
     * Method description
     *
     *
     * @param smc
     *
     * @return
     */
    @Override
    public boolean handleMessage(SOAPMessageContext smc) {

        Boolean outboundProperty =
            (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

        SOAPMessage msg = smc.getMessage();

        try {

            SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope();
            SOAPHeader header = envelope.getHeader();

            if (header == null) {

                envelope.addHeader();
                header = envelope.getHeader();
            }

            if (Boolean.TRUE.equals(outboundProperty)) {

                if (this.context != null) {

                    // <TransactionContext>
                    // <TransactionID>...</TransactionID>
                    // </TransactionContext>

                    SOAPElement contextNode = header.addChildElement(new QName(URI,
                                                  "TransactionContext"));
                    SOAPElement transIdNode = contextNode.addChildElement(new QName(URI,
                                                  "TransactionID"));

                    transIdNode.setTextContent(this.context.getTransId());

                    msg.saveChanges();

                    logger.debug("Outgoing Transaction Context {} sent.",
                                 this.context.getTransId());
                }

            } else {

                TransactionContext.Builder builder = new TransactionContext.Builder();

                NodeList nodes = header.getElementsByTagNameNS(URI, "*");

                for (int i = 0; i < nodes.getLength(); ++i) {

                    Node node = nodes.item(i);
                    String name = node.getLocalName();

                    logger.debug("Node-Name {}", name);

                    switch (name) {

                        case "TransactionID" :
                            builder.transId(node.getTextContent());

                            break;
                    }
                }

                this.context = builder.build();

                smc.put(TRANSACTION_CONTEXT, this.context);
                smc.setScope(TRANSACTION_CONTEXT, MessageContext.Scope.APPLICATION);

                logger.debug("Incoming Transaction Context {} saved.",
                             this.context.getTransId());
            }

        } catch (Exception ex) {

            logger.debug("Error in the client handler", ex);
        }

        return true;
    }
}
